package NWish
{
    import NWish.Interface.IApp;
    import NWish.Interface.ILogger;
    
    import away3d.cameras.Camera3D;
    import away3d.containers.View3D;
    
    import caurina.transitions.Tweener;
    
    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import flash.ui.Keyboard;
    
    import org.aswing.JToggleButton;
    import org.aswing.event.AWEvent;
	
	//Camera Hover Drag Controller
	public class CameraHDController
	{
		private var _app:IApp;
		
		//
		//private var _stage : Stage;
		private var _target : Vector3D = new Vector3D();
		private var _camera : Camera3D;
		private var _radius : Number = 1000;
		private var _speed : Number = .005;
		private var _dragSmoothing : Number = .1;
		private var _drag : Boolean;
		private var _referenceX : Number = 0;
		private var _referenceY : Number = 0;
		private var _xRad : Number = 0.04;
		private var _yRad : Number = -0.55;
		private var _targetXRad : Number = 0;
		private var _targetYRad : Number = .5;
        private var _targetRadius : Number = 1000;
		private var _moveSpeed:Number = 20;
		private var _moveSmoothing : Number = .1;
		
		//
		private var _cameraToggleButton:JToggleButton;

		
		public function CameraHDController(app)
		{
			//
			_app = app;
			
			//
			var menuBar:MenuBar = _app.getPlugin('MenuBar') as MenuBar;
			menuBar.settingMenu.addMenuItem("&Camera setting").addActionListener(_showSetting);

			//
			var menuBar:MenuBar = _app.getPlugin('MenuBar') as MenuBar;
			_cameraToggleButton = new JToggleButton("camera");
			_cameraToggleButton.y = 2;
			_cameraToggleButton.setToolTipText('Hot key ` is active. Hot key QWEASD is move camera');
			menuBar.addButton(_cameraToggleButton,'Group0',Keyboard.BACKQUOTE);//` key code is 192
			
			//test
			/*var b:JToggleButton = new JToggleButton("camera1");
			b.y = 2;
			menuBar.addButton(b,'Group0',49);//1 key code is 49*/
			
			
			//
			_app.NWEventDispatcher.addEventListener(NWEvent.CREATE_OBJECT,		onCreateObject,false,-1);
		}
		
		
		public function init()
		{
			//
			//_stage = parent.stage;
			_app.away3d.addEventListener(MouseEvent.MOUSE_DOWN, 	onMouseDown);
			_app.away3d.addEventListener(MouseEvent.MOUSE_UP, 		onMouseUp);
			_app.away3d.addEventListener(MouseEvent.MOUSE_WHEEL, 	onMouseWheel);
			_app.away3d.addEventListener(Event.ENTER_FRAME, 		onEnterFrame);
			
			_app.KBEventDispatcher.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			_app.KBEventDispatcher.addEventListener(KeyboardEvent.KEY_UP, 	onKeyUp);
			
		}
		
		public function destroy() : void
		{
			_app.away3d.removeEventListener(MouseEvent.MOUSE_DOWN, 	onMouseDown);
			_app.away3d.removeEventListener(MouseEvent.MOUSE_UP, 	onMouseUp);
			_app.away3d.removeEventListener(MouseEvent.MOUSE_WHEEL,	onMouseWheel);
			_app.away3d.removeEventListener(Event.ENTER_FRAME, 		onEnterFrame);
			
			_app.KBEventDispatcher.removeEventListener(KeyboardEvent.KEY_DOWN, 	onKeyDown);
			_app.KBEventDispatcher.removeEventListener(KeyboardEvent.KEY_UP, 	onKeyUp);
		}

		
		private function onCreateObject(e:NWEvent)
		{
			//
			if(e.objects is View3D)
				_camera = e.objects.camera;
		}
		
		private function get isSelected()
		{
			return _cameraToggleButton.isSelected();
		}

		private function _showSetting(e:Event)
		{
			ILogger.log('todo ...');
		}
		
		public function get dragSmoothing() : Number
		{
			return _dragSmoothing;
		}

		public function set dragSmoothing(value : Number) : void
		{
			_dragSmoothing = value;
		}


		public function get radius() : Number
		{
			return _targetRadius;
		}

		public function set radius(value : Number) : void
		{
			_targetRadius = value;
		}


		public function get speed() : Number
		{
			return _speed;
		}

		public function set speed(value : Number) : void
		{
			_speed = value;
		}
		
		public function get moveSpeed() : Number
		{
			return _moveSpeed;
		}
		
		public function set moveSpeed(value : Number) : void
		{
			_moveSpeed = value;
		}
		
		public function get moveSmoothing() : Number
		{
			return _moveSmoothing;
		}
		
		public function set moveSmoothing(value : Number) : void
		{
			_moveSmoothing = value;
		}
		

		public function get target() : Vector3D
		{
			return _target;
		}

		public function set target(value : Vector3D) : void
		{
			Tweener.addTween(_target,{time:1,/*transition:'linear',*/x:value.x,y:value.y,z:value.z});
		}


		private function onEnterFrame(event : Event) : void
		{
			if(_camera == null)
				return;
			
			
			updateToMove();
			if (_drag) updateRotationTarget();

            _radius = _radius + (_targetRadius - _radius)*dragSmoothing;
			_xRad = _xRad + (_targetXRad - _xRad)*dragSmoothing;
			_yRad = _yRad + (_targetYRad - _yRad)*dragSmoothing;

			// simple spherical position based on spherical coordinates
			var cy : Number = Math.cos(_yRad)*_radius;
			_camera.x = _target.x - Math.sin(_xRad)*cy;
			_camera.y = _target.y + Math.sin(_yRad)*_radius;
			_camera.z = _target.z - Math.cos(_xRad)*cy;
			_camera.lookAt(_target);
			
			//trace('_camera',_camera.x,_camera.y,_camera.z);
			//trace(_target);
		}


		private function updateRotationTarget() : void
		{
			var mouseX : Number = _app.rootSprite.mouseX;
			var mouseY : Number = _app.rootSprite.mouseY;
			var dx : Number = mouseX - _referenceX;
			var dy : Number = mouseY - _referenceY;
			var bound : Number = Math.PI * .5 - .05;

			_referenceX = mouseX;
			_referenceY = mouseY;
			_targetXRad += dx * _speed;
			_targetYRad += dy * _speed;
			if (_targetYRad > bound) _targetYRad = bound;
			else if (_targetYRad < -bound) _targetYRad = -bound;
		}

		private function onMouseDown(e : MouseEvent) : void
		{
			if(/*e.target != _stage ||*/ e.ctrlKey || e.shiftKey)
				return;
			
			if(isSelected == false)
				return;
			
			_drag = true;
			_referenceX = _app.rootSprite.mouseX;
			_referenceY = _app.rootSprite.mouseY;
		}
		
		private function onMouseUp(event : MouseEvent) : void
		{
			_drag = false;
		}
		
        private function onMouseWheel(event:MouseEvent) : void
        {
			//if(event.target != _stage)
			//	return;
			
			if(isSelected == false)
				return;
			
            _targetRadius -= event.delta*5;
        }
		
		//
		private var _q = false;//key code 81
		private var _w = false;//key code 87
		private var _e = false;//key code 69
		private var _a = false;//key code 65
		private var _s = false;//key code 83
		private var _d = false;//key code 68
		//private var _z = false;//key code 90
		//private var _x = false;//key code 88
		//private var _c = false;//key code 67
		private function onKeyDown(e:KeyboardEvent) : void
		{
			if(/*e.target != _stage ||*/ isSelected == false || e.ctrlKey || e.shiftKey)
				return;
			
				 if(e.keyCode == Keyboard.Q)_q = true;
			else if(e.keyCode == Keyboard.W)_w = true;
			else if(e.keyCode == Keyboard.E)_e = true;
			else if(e.keyCode == Keyboard.A)_a = true;
			else if(e.keyCode == Keyboard.S)_s = true;
			else if(e.keyCode == Keyboard.D)_d = true;
		}
		private function onKeyUp(e:KeyboardEvent) : void
		{
			if(/*e.target != _stage ||*/ isSelected == false || e.ctrlKey || e.shiftKey)
				return;
			
				 if(e.keyCode == Keyboard.Q)_q = false;
			else if(e.keyCode == Keyboard.W)_w = false;
			else if(e.keyCode == Keyboard.E)_e = false;
			else if(e.keyCode == Keyboard.A)_a = false;
			else if(e.keyCode == Keyboard.S)_s = false;
			else if(e.keyCode == Keyboard.D)_d = false;
		}
		
		private var _currMoveSpeed = 0.0;
		private function updateToMove() : void
		{
			_currMoveSpeed += _moveSpeed * _moveSmoothing;
			
			if(_currMoveSpeed > _moveSpeed)
				_currMoveSpeed = _moveSpeed;
			
			
			var ismove = false;
			if(_q)
			{
				ismove = true;
				_target.y += _currMoveSpeed;
			}
			if(_e)
			{
				ismove = true;
				_target.y -= _currMoveSpeed;
			}
			if(_w)
			{
				ismove = true;
				translateLocal(2, _currMoveSpeed);
			}
			if(_s)
			{
				ismove = true;
				translateLocal(2, -_currMoveSpeed);
			}
			if(_a)
			{
				ismove = true;
				translateLocal(0, -_currMoveSpeed);
			}
			if(_d)
			{
				ismove = true;
				translateLocal(0, _currMoveSpeed);
			}
			
			if(ismove == false)
				_currMoveSpeed = 0.0;
		}
		
		
		public function translateLocal(index, distance : Number) : void
		{
			var axis:Vector3D = new Vector3D();
			_camera.transform.copyRowTo(index, axis);
			
			axis.x *= distance;
			axis.y *= distance;
			axis.z *= distance;
			_target.x += axis.x;
			_target.y += axis.y;
			_target.z += axis.z;
		}
		
		public function translateLocal1(axis : Vector3D, distance : Number) : void
		{
			/*var _axis = _camera.transform.deltaTransformVector(axis);
			_axis *= distance;
			_target += _axis;*/
			
			
			//var x : Number = axis.x, y : Number = axis.y, z : Number = axis.z;
			//var len : Number = distance / Math.sqrt(x * x + y * y + z * z);
			
			/*var m : Matrix3D = new Matrix3D(_camera.transform.rawData);
			m.prependTranslation(x*len, y*len, z*len);
			m.copyRowTo(3, _target);*/
		}
	}
}
